﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Configuration;
using System.Net;
using System.Threading;

namespace ServidorDeComunicaciones
{
    class CommServer
    {
        TcpListener Servidor;
        int CantidadClientes;
        LocalQueue LocalQueue;
        RemClient r;

        public CommServer()
        {
            CantidadClientes = Int32.Parse(ConfigurationManager.AppSettings["CantidadClientes"]);

            Int32 Port = Int32.Parse(ConfigurationManager.AppSettings["TcpPort"]);
            string IPLocal = ConfigurationManager.AppSettings["IPLocal"];
            IPAddress LocalAddress = IPAddress.Parse(IPLocal);

            Servidor = new TcpListener(LocalAddress, Port);

            Servidor.Start();

            Console.WriteLine("Server started.");

            Thread[] threadPool = new Thread[CantidadClientes];
            r = new RemClient();
            for (int i = 0; i < threadPool.Length; i++)
            {
                threadPool[i] = new Thread(DoWork);
                threadPool[i].Start();
            }

            LocalQueue = new LocalQueue();
            Thread ThreadRecibir = new Thread(RecibirEncola);
            ThreadRecibir.Start();

           
        }

        public void DoWork()
        {
            try
            {
                // Buffer para lectura
                Byte[] BDatos = new Byte[256];
                
                // Entra en el loop
                while (true)
                {
                    Console.Write("Esperando conexión. \n");

                    TcpClient Cliente = Servidor.AcceptTcpClient();
                    Console.WriteLine("Conectado.");

                    // Crea Stream para lectura escritura
                    NetworkStream Stream = Cliente.GetStream();

                    //Espera datos
                    while (!Stream.DataAvailable) { }

                    int IDatos;

                    //Lee primer paquete de datos
                    IDatos = Stream.Read(BDatos, 0, BDatos.Length);

                    //Convierte a String
                    string SDatos = System.Text.Encoding.ASCII.GetString(BDatos);

                    //Obtener comando
                    var datos = SDatos.Split(';');
                    string Comando = datos[0];

                    switch (Comando)
                    {
                        case "05":
                            bool EmpezoCobrar = false;
                            int RecorridoAcumulado = 0;
                            string Estado = datos[1];
                            string IdCliente1 = datos[2];
                            string Recorrido = datos[3];
                            int RecorridoACobrar = 0;
                            Int32.TryParse(Recorrido, out RecorridoACobrar);
                            while (true && Comando == "05") //Thread que recibe los estados del Agente
                            {
                                //Alamcenar datos de estado o enviarlos a cobro real
                                if (Estado == "01")
                                {
                                    //RecorridoACobrar con IdCliente por remoting. 
                                    r.Enviar(IdCliente1 + ";" + RecorridoACobrar);
                                    RecorridoAcumulado += RecorridoACobrar;
                                    EmpezoCobrar = true;
                                }
                                else if (Estado == "00" && EmpezoCobrar)
                                {
                                    //Termino -> Enviar Cobro
                                    LocalQueue.SendMessage("C07", IdCliente1 + ";" + RecorridoAcumulado);
                                    EmpezoCobrar = false;
                                    RecorridoAcumulado = 0;
                                    RecorridoACobrar = 0;
                                }

                                //ACK
                                string SMensaje05 = "05;";
                                byte[] BMensaje05 = System.Text.Encoding.ASCII.GetBytes(SMensaje05);
                                Stream.Write(BMensaje05, 0, BMensaje05.Length);

                                while (!Stream.DataAvailable) { }

                                Byte[] BMensaje = new Byte[256];
                                Stream.Read(BMensaje, 0, BMensaje.Length);
                                string SMensaje = System.Text.Encoding.ASCII.GetString(BMensaje);
                                Console.WriteLine("Recibido estado: Cliente = " + SMensaje.Split(';')[2] +
                                    "- Estado = " + SMensaje.Split(';')[1] + "- Recorrido = " + SMensaje.Split(';')[3]);

                                datos = SMensaje.Split(';');
                                Comando = datos[0];
                                Estado = datos[1];
                                IdCliente1 = datos[2];

                                // Int32.TryParse(Recorrido, out RecorridoACalcular);
                                Recorrido = datos[3];
                                int RecorridoNuevo = 0;
                                Int32.TryParse(Recorrido, out RecorridoNuevo);
                                RecorridoACobrar = RecorridoNuevo - RecorridoAcumulado;


                            }
                            break;

                        case "02":
                            //Valida cliente
                            try
                            {
                                string IdCliente = SDatos.Split(';')[1];
                                string IPAgente = SDatos.Split(';')[2];
                                string Label = "C01";
                                string Datos = IdCliente + ";" + IPAgente + ";";
                                LocalQueue.SendMessage(Label, Datos);
                                string SMensaje02 = "OK;";
                                byte[] BMensaje02 = System.Text.Encoding.ASCII.GetBytes(SMensaje02);
                                Stream.Write(BMensaje02, 0, BMensaje02.Length);
                            }
                            catch (Exception e)
                            {
                                string SMensaje02 = "00;";
                                byte[] BMensaje02 = System.Text.Encoding.ASCII.GetBytes(SMensaje02);
                                Stream.Write(BMensaje02, 0, BMensaje02.Length);

                            }
                            break;

                        case "03":
                            //Desconectar
                            string SMensaje03 = "00;";
                            byte[] BMensaje03 = System.Text.Encoding.ASCII.GetBytes(SMensaje03);
                            Stream.Write(BMensaje03, 0, BMensaje03.Length);
                            break;

                        case "00":
                            //Disponible


                            break;

                        case "01":
                            //Ocupado
                            break;
                    }
                }
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }
            finally
            {
                // Stop listening for new clients.
                //Servidor.Stop();
            }
        }

        public static void EnviaRespuestaAgente(string label, string mensaje)
        {
            TcpClient Agente;
            string AgentIP = mensaje.Split(';')[0];
            string IdCliente = mensaje.Split(';')[1];
            string Respuesta = label;
            string Estado;
            int AgentTcpPort = Int32.Parse(ConfigurationManager.AppSettings["AgentTcpPort"]);
            Agente = new TcpClient(AgentIP, AgentTcpPort);
            NetworkStream Stream = Agente.GetStream();
            switch (Respuesta)
            {
                case "C02":
                    Estado = "01";
                    break;
                case "C04":
                    Estado = "06";
                    break;
                case "C05":
                    Estado = "07";
                    break;
                default:
                    Estado = "00";
                    break;
            }


            string SMensaje = Estado + ";" + IdCliente + ";";
            byte[] BMensaje = System.Text.Encoding.ASCII.GetBytes(SMensaje);
            Stream.Write(BMensaje, 0, BMensaje.Length);
        }

        public void RecibirEncola()
        {
            LocalQueue.ReceiveMessage();
        }
    }
}
